#ifndef string_H
#define string_H

#include <string.h>
#include "../os/os.h"
#include <fstream>

namespace sleek
{
    namespace core
    {
        namespace os
        {
            template<typename T>
            class string
            {
                public:
                    /*******************************************************************/
                        string()
                        {
                            str = 0;
                            free();
                        }
                        string(bool val)
                        {
                            str = 0;
                            if(val) *this = "true";
                            else    *this = "false";
                        }
                        string(int number)
                        {
                            str = 0;
                            T buffer[16];
                            snprintf(buffer,15, "%d", number);
                            *this = buffer;
                        }
                        string(unsigned int number)
                        {
                            str = 0;
                            T buffer[16];
                            snprintf(buffer,15, "%d", number);
                            *this = buffer;
                        }
                        string(double number)
                        {
                            str = 0;
                            T buffer[16];
                            snprintf(buffer,15, "%0.6f", number);
                            *this = buffer;
                        }
                        string(std::string chaine)
                        {
                            str = 0;
                            *this = chaine;
                        }
                        string(const string &chaine)
                        {
                            str = 0; free();
                            *this = chaine;
                        }
                        string(const T*other)
                        {
                            str = 0;
                            *this = other;
                        }
                        ~string(){ if(str) delete[] str; }
                        inline void print() { std::cout << c_str() << std::endl; }
                    /*******************************************************************/
                        inline string<T> operator + (const string<T> other)
                        {
                            string<T> _this = *this;
                            _this += other;
                            return _this;
                        }
                        inline void operator += (std::string ohter)
                        {
                            *this += ohter.c_str();
                        }
                        inline T& operator[] (unsigned short pos)
                        {
                            return str[pos];
                        }
                        inline void operator += (const string<T> other)
                        {
                            add(other.str,other.sze);
                            //reserve(other.sze);
                            //for( register unsigned short i = 0; i<other.sze; ++i)
                                //str[i+(sze-other.sze)] = (T)other.str[i];
                        }
                        inline void operator += (const T*other)
                        {
                            add(other,strsize(other));
                        }
                        template<typename P> inline void add(const P*other,unsigned short s)
                        {
                            if(s<=0) return;
                            T*str_tmp = new T[sze+1];
                                memcpy(str_tmp,str,sze+1);         free(sze+s);   memcpy(str,str_tmp,sze-s);
                                for(unsigned short i = 0; i<s; ++i) str[sze-s+i] = (T)other[i];
                            delete[] str_tmp;
                        }
                    /*******************************************************************/
                        template<typename B>
                        void operator = (const string<B>&other)
                        {
                            free(other.sze);
                            memcpy(str,other.str,other.sze);
                        }
                        void operator = (std::string other)
                        {
                            free(other.size());
                            memcpy(str,other.c_str(),other.size());
                        }
                        void operator = (const string &other)
                        {
                            free(other.sze);
                            memcpy(str,other.str,other.sze);
                        }
                        void operator = (const T*other)
                        {
                            unsigned short s = strsize(other);
                            free(s);          memcpy(str,other,s);
                        }
                    /*******************************************************************/
                        bool operator != (const T       *cmp) const { return !(*this == cmp); }
                        bool operator != (const string &cmp) const { return !(*this == cmp); }
                        bool operator == (const string &cmp) const
                        {
                            bool ok = true;
                            if(sze != cmp.sze) return false;
                            for( unsigned short i = 0; i<sze; ++i)
                                if(str[i] != cmp.str[i]) { ok = false; break; }
                            return ok;
                        }
                        bool operator == (const T*cmp) const
                        {
                            bool ok = true;
                            for( unsigned short i = 0; i<sze; ++i)
                                if(str[i] != cmp[i]) { ok = false; break; }
                            return ok;
                        }
                    /*******************************************************************/
                        inline long find(const T*fd){ T *p = strstr(str,fd); if(!p)return -1; return p-str; }
                        inline long find(const T*fd,unsigned short pos)
                        {
                            --pos;
                            unsigned short taille = strsize(fd);
                            while(++pos < sze)
                            {
                                for(unsigned short i = 0; i < taille; ++i)
                                {
                                    if(str[pos+i] != fd[i]) break;
                                    if(i == taille-1)       return pos;
                                }
                            }
                            return -1;
                        }
                        inline long find_backward(const T*fd,unsigned short pos)
                        {
                            --pos;
                            unsigned short taille = strsize(fd);
                            while(--pos < sze)
                            {
                                for(unsigned short i = taille; i > 0; ++i)
                                {
                                    if(str[pos-i] != fd[i]) break;
                                    if(i == taille-1)       return pos;
                                }
                            }
                            return -1;
                        }
                        inline void Crypt(string<T> code)// XOR crypt
                        {
                            unsigned short j = 0;
                            for(unsigned short i = 0; i<sze; ++i)
                            {
                                printf("%c",code[j]);
                                str[i] ^= 0^code[j];
                                if(j++ == code.sze-1) j=0; // -1 because + '\0'
                            }
                        }
                    /*******************************************************************/
                        inline void insert(string car,unsigned short pos)
                        {
                            for( long j = 0; j<car.size(); ++j) insert(car[j],pos+j);
                        }
                        inline void insert(const T car,unsigned short pos)
                        {
                            reserve(1);
                            for( long i = sze; i<pos-1; --i) str[i+1] = str[i];
                            str[pos] = car;
                        }
                        inline void remove(unsigned short spk,unsigned short size)
                        {
                            for(unsigned short i = 0; i<size; ++i) remove(spk);
                        }
                        inline void remove(unsigned short spk)
                        {
                            for(unsigned short i = spk-1; i<sze; ++i) str[i] = str[i+1];
                                reserve(-1);
                        }
                        inline void reserve(unsigned short spk)
                        {
                            if(sze > 0 && spk != 0)
                            {
                                T *strTmp = new T[sze];   memcpy(strTmp,str,sze); delete [] str;
                                str = new T[sze+spk+1];   memcpy(str,strTmp,sze); delete [] strTmp;
                                return;
                            }
                            if(spk > 0 && sze <= 0)
                            {
                                str = new T[spk];     str[sze+spk] = '\0';      sze += spk;
                            }
                        }
                    /*******************************************************************/
                        void free(unsigned short lenght = 0)
                        {
                            if(str) delete[] str;
                            str = new T[lenght+1];
                            if(!str) { printf("memory overflow ! can't make \"new char[%d]\"\n",lenght+1); }
                            str[lenght] = '\0';
                            sze = lenght;
                        }
                        inline const T*c_str()
                        {
                            return str;
                        }
                        unsigned short size()
                        {
                            return sze;
                        }
                        inline string<T> subStr(unsigned short begin, unsigned short length)
                        {
                            if (length+begin > sze)                length = sze-begin;
                            string o;                             o.free(length);
                            for (unsigned short i=0; i<length; ++i) o.str[i] = str[i+begin];
                            return o;
                        }
                    /*********************************************************************/
                        inline void saveToFile(string<char> filename,bool isBinary = false)
                        {
                            std::ofstream myFile;

                            if(isBinary) myFile.open(filename.c_str(),std::ios::out | std::ios::binary);
                            else myFile.open(filename.c_str(),std::ios::out);

                            myFile.write(c_str(),size());
                            myFile.close();
                        }
                        inline string<T> loadFromFile(string<char> file,bool isBinary = false)
                        {
                            free(0);
                            std::ifstream myFile;
                             if(isBinary) myFile.open(file.c_str(),std::ios::in | std::ios::binary);
                             else  myFile.open(file.c_str(),std::ios::in);
                                while(myFile.eof() != true && myFile.is_open())
                                {
                                    T *buffer = new T[512];
                                    memset(buffer,0,511);
                                    myFile.read(buffer,511);
                                    *this += buffer;
                                    delete[] buffer;
                                }
                            myFile.close();
                            return this;
                        }
                    /*******************************************************************/
                private:
                    unsigned long sze;
                    mutable T *str;
            };
            typedef string<char>    stringc;
            typedef string<wchar_t> stringw;
        }
    }
}
#endif // string_H
